﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StoreyManagementDlg.h"
#include "ui_StoreyManagementDlg.h"
#include "UiCommonDialog.h"
#include "IPickPointAction.h"
#include "GmStyleSheetHelper.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "IGenericElement.h"
#include "ILevel.h"
#include "IElementBasicInformation.h"
#include "IDocument.h"
#include "ILevelNameManager.h"
#include "BuildingUtils.h"
#include "IBuilding.h"
#include "IUiView.h"
#include "IModelView.h"
#include "LevelUtils.h"
#include "IGbmpModelView.h"
#include "GbmpModelViewUtil.h"
#include "qevent.h"


#include "IUiDocumentViewManager.h"
#include "GbmpDocUtils.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

#define LEVEL_NAME_DATA_ROLE (Qt::UserRole + 1)

namespace
{
    gcmp::IUiView* GetCurrentUiView()
    {
        IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
        DBG_WARN_AND_RETURN_UNLESS(pUiDocViewMgr, nullptr, L"pUiDocViewMgr为空",L"GDMPLab",L"2024-03-30");

        return pUiDocViewMgr->GetCurrentUiView();
    }

    bool CanBuildingBeDeleted(IDocument* pDoc, ElementId buildingId)
    {
        IUiView* pCurrentUIView = GetCurrentUiView();
        DBG_WARN_AND_RETURN_UNLESS(pCurrentUIView, true, L"当前UI视图为空？",L"GDMPLab",L"2024-03-30");

        const IModelView* pModelView = pCurrentUIView->GetModelView();
        DBG_WARN_AND_RETURN_UNLESS(pModelView, true, L"当前模型视图为空？",L"GDMPLab",L"2024-03-30");

        const IGbmpModelView* pView = GbmpModelViewUtil::GetGbmpModelView(pModelView);
        if (pView)
        {
            ILevel* pLevel = LevelUtils::GetLevelById(pDoc, pView->GetWorkLevelId());
            if (pLevel && pLevel->GetBuildingId() == buildingId)
            {
                UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"当前激活视图为对应单体下的视图，请先切换视图后再次删除单体。"), (int)UiCommonDialog::ButtonType::OK);
                return false;
            }
        }
        return true;
    }

    // 是否有比preName高的标高是属于单体的
    bool HasStoreyAboveLevel(const std::list<StoreyStruct>& storeys, const std::wstring& preName, bool includePreName)
    {
        auto iter = storeys.begin();
        for (; iter != storeys.end(); ++iter)
        {
            if (iter->name == preName)
            {
                if (includePreName == false)
                {
                    ++iter;
                }
                break;
            }
        }

        for (; iter != storeys.end(); ++iter)
        {
            if (iter->levelId.IsValid())
            {
                return true;
            }
        }

        return false;
    }
    
}

void StoreyList::AddStorey(const std::wstring& name, double elevation, ElementId levelId)
{
    // 如果目前没有楼层， 则直接添加， 并更新起始高度
    if (m_storeyList.empty())
    {
        StoreyStruct storey(name, 0, levelId);
        m_storeyList.insert(m_storeyList.begin(), storey);
        m_startElevation = elevation;
        return;
    }

    // 如果添加的标高比现有的最低的标高还低， 则直接添加， 并更新起始高度
    if (elevation < m_startElevation)
    {
        StoreyStruct storey(name, m_startElevation - elevation, levelId);
        m_storeyList.insert(m_storeyList.begin(), storey);
        m_startElevation = elevation;
    }
    else
    {
        double storeyElevation = m_startElevation;
        for (auto iter = m_storeyList.begin(); iter != m_storeyList.end(); ++iter)
        {
            if (elevation < storeyElevation + iter->storeyHeight)
            {
                StoreyStruct storey(name, storeyElevation + iter->storeyHeight - elevation, levelId);
                m_storeyList.insert(iter, storey);
                
                iter->storeyHeight = elevation - storeyElevation;

                return;
            }

            storeyElevation += iter->storeyHeight;
        }

        // 如果添加的标高比现有的都高， 则修改当前最高的标高的层高， 添加这个新的标高
        auto iter = --m_storeyList.end();
        iter->storeyHeight = elevation - storeyElevation;
        StoreyStruct storey(name, 0, levelId);
        m_storeyList.push_back(storey);
    }
}

void StoreyList::AddStoreyAbove(const std::wstring& name, double storeyHeight, const std::wstring& preName)
{
    for (auto iter = m_storeyList.begin(); iter != m_storeyList.end(); ++iter)
    {
        if (iter->name == preName)
        {
            if (iter ==  --m_storeyList.end())
            {
                iter->storeyHeight = storeyHeight;
                StoreyStruct storey(name, 0, ElementId::InvalidID);
                m_storeyList.insert(++iter, storey);
            }
            else
            {
                StoreyStruct storey(name, storeyHeight, ElementId::InvalidID);
                m_storeyList.insert(++iter, storey);
            }

            return;
        }
    }
}

void StoreyList::AddStoreyBelow(const std::wstring& name, double storeyHeight, const std::wstring& postName)
{
    for (auto iter = m_storeyList.begin(); iter != m_storeyList.end(); ++iter)
    {
        if (iter->name == postName)
        {
            StoreyStruct storey(name, storeyHeight, ElementId::InvalidID);
            if (iter == m_storeyList.begin())
            {
                m_storeyList.push_front(storey);
            }
            else
            {
                m_storeyList.insert(iter, storey);
            }
            m_startElevation = m_startElevation - storeyHeight;
            return;
        }
    }
}

void StoreyList::RemoveStorey(const std::wstring& name)
{
    for (auto iter = m_storeyList.begin(); iter != m_storeyList.end(); ++iter)
    {
        if (iter->name == name)
        {
            m_storeyList.erase(iter);
            return;
        }
    }
}

double StoreyList::GetElevation(const StoreyStruct& storey) const
{
    double startElevation = m_startElevation;
    for (auto iter = m_storeyList.begin(); iter != m_storeyList.end(); ++iter)
    {
        if (iter->name == storey.name)
        {
            return startElevation;
        }

        startElevation += iter->storeyHeight;
    }

    return startElevation;
}

std::set<std::wstring> StoreyList::GetStoreyNames() const
{
    std::set<std::wstring> names;
    for (auto iter = m_storeyList.begin(); iter != m_storeyList.end(); ++iter)
    {
        names.insert(iter->name);
    }

    return names;
}

StoreyManagementDlg::StoreyManagementDlg(IDocument* pDoc, QWidget *parent) 
    : QDialog(parent, Qt::FramelessWindowHint)
    , ui(NEW_AS_OWNER_PTR(Ui::StoreyManagementDlg))
    , m_pDoc(pDoc)
{
    ui->setupUi(this);
    std::wstring styleSheetStr = GmStyleSheetHelper::Instance()->GetCurrentStyleData();
    setStyleSheet(QString::fromStdWString(styleSheetStr));
    ui->gbmp_title->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    ui->gbmp_title->setIconVisible(false);
    ui->gbmp_title->setMaxButtonVisible(false);
    ui->gbmp_title->setMinButtonVisible(false);
    ui->gbmp_title->setText(QString::fromStdWString(GBMP_TR(L"楼层管理")));
    this->setProperty("use_gbmp_title", true);
    connect(ui->okButton, SIGNAL(clicked()), this, SLOT(OKButtonPushed()));
    connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(CancelButtonPushed()));

    connect(ui->gbmp_title, &GmTitleBar::closeRequested, this, &StoreyManagementDlg::reject);
    connect(ui->gbmp_title, &GmTitleBar::moveRequested, this, &StoreyManagementDlg::onMoveRequested);

    connect(ui->addStoreyAboveButton, SIGNAL(clicked()), this, SLOT(OnAddStoreyAboveButtonPushed()));
    connect(ui->addStoreyBelowButton, SIGNAL(clicked()), this, SLOT(OnAddStoreyBelowButtonPushed()));
    connect(ui->deleteStoreyButton, SIGNAL(clicked()), this, SLOT(OnDeleteStoreyButtonPushed()));

    connect(ui->addBuildingButton, SIGNAL(clicked()), this, SLOT(OnAddBuildingButtonPushed()));
    connect(ui->deleteBuildingButton, SIGNAL(clicked()), this, SLOT(OnDeleteBuildingButtonPushed()));

    connect(ui->buildingListWidget, SIGNAL(itemClicked(QListWidgetItem *)), this, SLOT(OnBuildingListItemClicked(QListWidgetItem *)));

    std::vector<IBuilding*> buildings = BuildingUtils::GetAllBuildings(pDoc);
    FOR_EACH(pBuilding, buildings)
    {       
        IElementBasicInformation* pBasicInfo = pBuilding->GetOwnerElement()->GetBasicInformation();
        DBG_WARN_AND_CONTINUE_UNLESS(pBasicInfo, L"Elemeng没有IElementBasicInformation",L"GDMPLab",L"2024-03-30");
        m_buildingList.push_back(BuildingStruct(pBasicInfo->GetName(), pBasicInfo->GetElementId()));
    }

    std::vector<IElement*> pElements = gcmp::GbmpDocUtils::GetElementsByCategory(m_pDoc, BuiltInCategoryUniIdentities::BICU_NEW_ELEVATION);
    FOR_EACH(pElement, pElements)
    {
        if (IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElement))
        {
            if (ILevel* pLevel = quick_cast<ILevel>(pGenericElement->GetExternalObject()))
            {
                if (pLevel->GetBuildingId().IsValid())
                {
                    StoreyList& storeyList = GetStoreyListByBuildingId(pLevel->GetBuildingId());
                    storeyList.AddStorey(pGenericElement->GetBasicInformation()->GetName(), pLevel->GetElevation(), pGenericElement->GetElementId());
                }
            }
        }
    }

    InitDialog();
}

StoreyManagementDlg::~StoreyManagementDlg()
{

}

void StoreyManagementDlg::InitValidators()
{
    m_opValidateHelper = NEW_AS_OWNER_PTR(LineEditValidateHelper, this);
    m_startIndexValidator = NumberValidator<int>(-50, 200, GBMP_TR(L"请输入[-50,200]的整数！"), true, true);
    m_storeyNumValidator = NumberValidator<int>(1, 500, GBMP_TR(L"请输入[1,500]的正整数！"), true, true);
    m_heightValidator = NumberValidator<double>(0, 100, GBMP_TR(L"请输入[0,100]的数！！"), true, true);

    m_validators.insert(std::make_pair(ui->startIndexLineEdit, &m_startIndexValidator));
    m_validators.insert(std::make_pair(ui->storeyNumLineEdit, &m_storeyNumValidator));
    m_validators.insert(std::make_pair(ui->storeyHeightLineEdit, &m_heightValidator));

    m_opValidateHelper->SetValidators(m_validators);
}

void StoreyManagementDlg::InitDialog()
{
    // Set Header
    ui->storeyTable->setColumnCount(4);

    QStringList List;
    List << QString::fromStdWString(GBMP_TR(L"序号")) << QString::fromStdWString(GBMP_TR(L"楼层名称"))
        << QString::fromStdWString(GBMP_TR(L"标高")) << QString::fromStdWString(GBMP_TR(L"层高"));
    ui->storeyTable->setHorizontalHeaderLabels(List);
    ui->storeyTable->model()->setHeaderData(0, Qt::Horizontal, List[0], Qt::AccessibleDescriptionRole);
    ui->storeyTable->model()->setHeaderData(1, Qt::Horizontal, List[1], Qt::AccessibleDescriptionRole);
    ui->storeyTable->model()->setHeaderData(2, Qt::Horizontal, List[2], Qt::AccessibleDescriptionRole);
    ui->storeyTable->model()->setHeaderData(3, Qt::Horizontal, List[3], Qt::AccessibleDescriptionRole);
    // 支持日志
    ui->storeyTable->model()->setHeaderData(0, Qt::Horizontal, QString::fromStdWString(GBMP_TR(L"序号")), Qt::AccessibleDescriptionRole);
    ui->storeyTable->model()->setHeaderData(1, Qt::Horizontal, QString::fromStdWString(GBMP_TR(L"楼层名称")), Qt::AccessibleDescriptionRole);
    ui->storeyTable->model()->setHeaderData(2, Qt::Horizontal, QString::fromStdWString(GBMP_TR(L"标高")), Qt::AccessibleDescriptionRole);
    ui->storeyTable->model()->setHeaderData(3, Qt::Horizontal, QString::fromStdWString(GBMP_TR(L"层高")), Qt::AccessibleDescriptionRole);

    ui->storeyTable->setSelectionBehavior(QAbstractItemView::SelectRows); //设置选择行为，以行为单位
    ui->storeyTable->setSelectionMode(QAbstractItemView::SingleSelection); //设置选择模式，选择单行

    UpdateBuildingList();
    UpdateStoreyTable();

    BuildingStruct& building = GetCurrentBuildingStruct();
    int startIndex = ILevelNameManager::Get(m_pDoc)->GetNumber(building.buildingId);
    startIndex = startIndex >= 0 ? startIndex + 1 : startIndex - 1;
    ui->startIndexLineEdit->setText(QString::number(startIndex));

    ui->storeyHeightLineEdit->setText(QString::number(3, 'f', 3));

    ui->storeyNumLineEdit->setText(QString::number(3));

    ui->prefixLineEdit->setText(QString::fromStdWString(ILevelNameManager::Get(m_pDoc)->GetPrefix(building.buildingId)));
    ui->postfixLineEdit->setText(QString::fromStdWString(ILevelNameManager::Get(m_pDoc)->GetSuffix(building.buildingId)));

    InitValidators();
}

void StoreyManagementDlg::UpdateStoreyTable(const std::wstring& selectedStoreyName)
{
    disconnect(ui->storeyTable, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(OnStoreyTableItemChanged(QTableWidgetItem*)));

    StoreyList& currentStoreyList = GetCurrentStoreyList();
    const std::list<StoreyStruct>& storeyList = currentStoreyList.GetStoryList();
    double elevation = currentStoreyList.GetStartElevation() / 1000; // 转换成米

    int rowCount = (int)storeyList.size();
    int row = rowCount - 1;
    ui->storeyTable->setRowCount(rowCount);
    for (auto iter = storeyList.begin(); iter != storeyList.end(); ++iter)
    {
        if (OwnerPtr<QTableWidgetItem> pTableItem = NEW_AS_OWNER_PTR(QTableWidgetItem))
        {
            pTableItem->setFlags(pTableItem->flags() & (~Qt::ItemIsEditable));
            pTableItem->setText(QString::number(rowCount - row));
            ui->storeyTable->setItem(row, 0, TRANSFER_OWNERSHIP_TO_THIRD_PARTY(pTableItem));
        }

        if (OwnerPtr<QTableWidgetItem> pTableItem = NEW_AS_OWNER_PTR(QTableWidgetItem))
        {
            pTableItem->setText(QString::fromStdWString(iter->name));
            pTableItem->setData(LEVEL_NAME_DATA_ROLE, QVariant(QString::fromStdWString(iter->name)));
            ui->storeyTable->setItem(row, 1, TRANSFER_OWNERSHIP_TO_THIRD_PARTY(pTableItem));
        }

        if (OwnerPtr<QTableWidgetItem> pTableItem = NEW_AS_OWNER_PTR(QTableWidgetItem))
        {
            if (row != rowCount - 1)
            {
                pTableItem->setFlags(pTableItem->flags() & (~Qt::ItemIsEditable));
            }
            pTableItem->setText(QString::number(elevation, 'f', 3));
            ui->storeyTable->setItem(row, 2, TRANSFER_OWNERSHIP_TO_THIRD_PARTY(pTableItem));
        }

        if (OwnerPtr<QTableWidgetItem> pTableItem = NEW_AS_OWNER_PTR(QTableWidgetItem))
        {
            if (row == 0)
            {
                pTableItem->setFlags(pTableItem->flags() & (~Qt::ItemIsEditable));
            }
            pTableItem->setText(QString::number(iter->storeyHeight / 1000, 'f', 3));
            ui->storeyTable->setItem(row, 3, TRANSFER_OWNERSHIP_TO_THIRD_PARTY(pTableItem));
        }
        elevation = elevation + iter->storeyHeight / 1000;
        // 支持日志
        OwnerPtr<QTableWidgetItem> opVerticalHeaderItem = NEW_AS_OWNER_PTR(QTableWidgetItem);
        opVerticalHeaderItem->setText(QString::number(row, 10));
        ui->storeyTable->setVerticalHeaderItem(row, TRANSFER_OWNERSHIP_TO_THIRD_PARTY(opVerticalHeaderItem));
        ui->storeyTable->model()->setHeaderData(row, Qt::Vertical, QString::number(row), Qt::AccessibleDescriptionRole);

        --row;
    }

    int selectedRow = 0;
    if (selectedStoreyName.empty() == false)
    {
        for (int index = 0; index < rowCount; ++index)
        {
            QTableWidgetItem* pItem = ui->storeyTable->item(index, 1);
            if (pItem && pItem->text().toStdWString() == selectedStoreyName)
            {
                selectedRow = pItem->row();
                break;
            }
        }
    }

    ui->storeyTable->setCurrentCell(selectedRow, 1);

connect(ui->storeyTable, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(OnStoreyTableItemChanged(QTableWidgetItem*)));
}

void StoreyManagementDlg::UpdateBuildingList(const std::wstring& selectedBuildingName)
{
    disconnect(ui->buildingListWidget, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(OnBuildingListItemChanged(QListWidgetItem*)));

    ui->buildingListWidget->clear();

    FOR_EACH(building, m_buildingList)
    {
        OwnerPtr<QListWidgetItem> buildingItem = NEW_AS_OWNER_PTR(QListWidgetItem, ui->buildingListWidget);
        buildingItem->setText(QString::fromStdWString(building.name));
        buildingItem->setFlags(buildingItem->flags() | (Qt::ItemIsEditable));
        ui->buildingListWidget->addItem(TRANSFER_OWNERSHIP_TO_THIRD_PARTY(buildingItem));
    }

    int selectedRow = 0;
    if (selectedBuildingName.empty() == false)
    {
        for (int index = 0; index < ui->buildingListWidget->count(); ++index)
        {
            QListWidgetItem* pItem = ui->buildingListWidget->item(index);
            if (pItem && pItem->text().toStdWString() == selectedBuildingName)
            {
                selectedRow = index;
                break;
            }
        }
    }
    QListWidgetItem* pItem = ui->buildingListWidget->item(selectedRow);
    if (pItem)
    {
        m_currentBuildingName = pItem->text().toStdWString();
        ui->buildingListWidget->setCurrentRow(selectedRow);
    }

    connect(ui->buildingListWidget, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(OnBuildingListItemChanged(QListWidgetItem*)));
}

void StoreyManagementDlg::OKButtonPushed()
{
    // 检测项目中所有的标高是否有重名
    std::set<std::wstring> levelNames;
    std::vector<const ILevel*> levels = LevelUtils::GetStoreyLevelsInBuilding(m_pDoc, ElementId::InvalidID);
    FOR_EACH(pLevel, levels)
    {
        if (pLevel && pLevel->GetName().empty() == false)
        {
            levelNames.insert(pLevel->GetName());
        }
    }

    std::set<std::wstring> allNames;
    FOR_EACH(buildingStruct, m_buildingList)
    {
        std::vector<std::wstring> intersection;
        std::set<std::wstring> levelNamesInBuilding = buildingStruct.storeyList.GetStoreyNames();
        std::set_intersection(levelNames.begin(), levelNames.end(), levelNamesInBuilding.begin(), levelNamesInBuilding.end(), std::back_inserter(intersection));
        if (intersection.size() > 0)
        {
            UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"楼层列表中存在与视图中已有标高名称重复，请重新输入！"), (int)UiCommonDialog::ButtonType::OK);
            return;
        }

        std::set_intersection(allNames.begin(), allNames.end(), levelNamesInBuilding.begin(), levelNamesInBuilding.end(), std::back_inserter(intersection));
        if (intersection.size() > 0)
        {
            UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"不同单体之间的楼层名存在重复，请重新输入！"), (int)UiCommonDialog::ButtonType::OK);
            return;
        }
        allNames.insert(levelNamesInBuilding.begin(), levelNamesInBuilding.end());
    }

    QDialog::accept();
}

void StoreyManagementDlg::CancelButtonPushed()
{
    QDialog::reject();
}

void StoreyManagementDlg::onMoveRequested(const QPoint& cursorPos, const QPoint& offset)
{
    Q_UNUSED(cursorPos);
    move(pos() + offset);
}

void StoreyManagementDlg::OnAddStoreyAboveButtonPushed()
{
    if (CheckAddStoreyInput() == false)
    {
        return;
    }

    std::wstring prefix = ui->prefixLineEdit->text().toStdWString();
    int index = ui->startIndexLineEdit->text().toInt();
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_startIndexValidator.ValidateValue(index), L"起始的Index值不符合设计值",L"GDMPLab",L"2024-03-30");
    std::wstring postfix = ui->postfixLineEdit->text().toStdWString();

    DBG_WARN_AND_RETURN_VOID_UNLESS(m_heightValidator.ValidateValue(ui->storeyHeightLineEdit->text().toDouble()), L"标高高度值不符合设计值",L"GDMPLab",L"2024-03-30");
    double height = ui->storeyHeightLineEdit->text().toDouble() * 1000; // 转换成毫米

    int storeyNum = ui->storeyNumLineEdit->text().toInt();
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_storeyNumValidator.ValidateValue(storeyNum), L"层数值不符合设计值",L"GDMPLab",L"2024-03-30");

    bool shouldAddBuildingAsPrefix = ui->buildingInPrefixCheckBox->isChecked();

    std::vector<std::wstring> newStoreys;
    for (int ii = 0; ii < storeyNum; ++ii)
    {
        std::wstring name = shouldAddBuildingAsPrefix ? m_currentBuildingName + L"-" : L"";
        name += prefix + StringUtil::ToWString(index + ii) + postfix;
        if (IsLevelNameExisted(name))
        {
            UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"插入楼层与楼层列表中已有名称重复，请重新输入！"), (int)UiCommonDialog::ButtonType::OK);
            return;
        }

        newStoreys.push_back(name);
    }

    int row = ui->storeyTable->currentRow();
    QTableWidgetItem *item = ui->storeyTable->item(row, 1);
    std::wstring preName = item->text().toStdWString();

    StoreyList& currentStoreyList = GetCurrentStoreyList();
    if (HasStoreyAboveLevel(currentStoreyList.GetStoryList(), preName, false))
    {
        if (UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"前插入楼层会影响项目中已创建楼层的标高值，是否继续？"), (int)UiCommonDialog::ButtonType::OK | (int)UiCommonDialog::ButtonType::Cancel) != UiCommonDialog::ButtonType::OK)
        {
            return;
        }
    }

    FOR_EACH(name, newStoreys)
    {
        currentStoreyList.AddStoreyAbove(name, height, preName);
        preName = name;
    }

    UpdateStoreyTable(*--newStoreys.end());
    UpdateStartIndexLineEdit(index + storeyNum - 1);
}

void StoreyManagementDlg::OnAddStoreyBelowButtonPushed()
{
    if (CheckAddStoreyInput() == false)
    {
        return;
    }

    std::wstring prefix = ui->prefixLineEdit->text().toStdWString();
    int index = ui->startIndexLineEdit->text().toInt();
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_startIndexValidator.ValidateValue(index), L"起始的Index值不符合设计值",L"GDMPLab",L"2024-03-30");
    std::wstring postfix = ui->postfixLineEdit->text().toStdWString();

    DBG_WARN_AND_RETURN_VOID_UNLESS(m_heightValidator.ValidateValue(ui->storeyHeightLineEdit->text().toDouble()), L"标高高度值不符合设计值",L"GDMPLab",L"2024-03-30");
    double height = ui->storeyHeightLineEdit->text().toDouble() * 1000; // 装换成毫米

    int storeyNum = ui->storeyNumLineEdit->text().toInt();
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_storeyNumValidator.ValidateValue(storeyNum), L"层数值不符合设计值",L"GDMPLab",L"2024-03-30");
    
    bool shouldAddBuildingAsPrefix = ui->buildingInPrefixCheckBox->isChecked();

    StoreyList& currentStoreyList = GetCurrentStoreyList();
    std::set<std::wstring> storeyNames = currentStoreyList.GetStoreyNames();

    std::vector<std::wstring> newStoreys;
    for (int ii = 0; ii < storeyNum; ++ii)
    {
        std::wstring name = shouldAddBuildingAsPrefix ? m_currentBuildingName + L"-" : L"";
        name += prefix + StringUtil::ToWString(index - ii) + postfix;
        if (storeyNames.find(name) != storeyNames.end())
        {
            UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"插入楼层与楼层列表中已有名称重复，请重新输入！"), (int)UiCommonDialog::ButtonType::OK);
            return;
        }

        newStoreys.push_back(name);
    }

    std::wstring preName = GetCurrentStoreyName();
    if (HasStoreyAboveLevel(currentStoreyList.GetStoryList(), preName, true))
    {
        if (UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"前插入楼层会影响项目中已创建楼层的标高值，是否继续？"), (int)UiCommonDialog::ButtonType::OK | (int)UiCommonDialog::ButtonType::Cancel) != UiCommonDialog::ButtonType::OK)
        {
            return;
        }
    } 

    FOR_EACH(name, newStoreys)
    {
        currentStoreyList.AddStoreyBelow(name, height, preName);
        preName = name;
    }

    UpdateStoreyTable(*--newStoreys.end());
    UpdateStartIndexLineEdit(index - storeyNum  + 1);
}

void StoreyManagementDlg::OnDeleteStoreyButtonPushed()
{
    std::wstring name = GetCurrentStoreyName();
    DBG_WARN_AND_RETURN_VOID_UNLESS(name.empty() == false, L"当前的楼层名字为空",L"GDMPLab",L"2024-03-30");

    std::vector<IElement*> pElements = gcmp::GbmpDocUtils::GetElementsByCategory(m_pDoc, BuiltInCategoryUniIdentities::BICU_NEW_ELEVATION);
    FOR_EACH(pElement, pElements)
    {
        if (pElement->GetBasicInformation()->GetName() == name)
        {
            UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"选中项中包含项目中已创建的楼层，请至立面视图中删除"), (int)UiCommonDialog::ButtonType::OK);
            return;
        }
    }

    StoreyList& currentStoreyList = GetCurrentStoreyList();
    if (currentStoreyList.GetStoreyCount() < 2)
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"无法清空楼层列表，请至少需保留一个楼层！"), (int)UiCommonDialog::ButtonType::OK);
        return;
    }
    currentStoreyList.RemoveStorey(name);
    UpdateStoreyTable();
}

void StoreyManagementDlg::OnAddBuildingButtonPushed()
{
    const QListWidgetItem* pItem = ui->buildingListWidget->currentItem();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pItem, L"当前行为空",L"GDMPLab",L"2024-03-30");

    std::wstring buildingName = pItem->text().toStdWString() + L"_新建";
    while (IsBuildingNameExisted(buildingName))
    {
        buildingName += +L"_新建";
    }
    BuildingStruct buildingStruct(buildingName, ElementId::InvalidID);
    buildingStruct.storeyList.AddStorey(buildingName + L"-楼层 1", 0.0, ElementId::InvalidID);

    for(auto iter = m_buildingList.begin(); iter != m_buildingList.end(); ++iter)
    {
        if (iter->name == pItem->text().toStdWString())
        {
            m_buildingList.insert(++iter, buildingStruct);
            break;
        }
    }

    UpdateBuildingList(buildingStruct.name);
    UpdateStoreyTable();
    UpdateStartIndexLineEdit(1);
}

void StoreyManagementDlg::OnDeleteBuildingButtonPushed()
{
    if (m_buildingList.size() < 2)
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"无法清空单体，请至少需保留一个单体！"), (int)UiCommonDialog::ButtonType::OK);
        return;
    }

    const QListWidgetItem* pItem = ui->buildingListWidget->currentItem();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pItem, L"当前行为空",L"GDMPLab",L"2024-03-30");

    auto iter = m_buildingList.begin();
    std::wstring currentName = pItem->text().toStdWString();
    for (; iter != m_buildingList.end(); ++iter)
    {
        if (iter->name == currentName)
        {
            break;
        }
    }
    DBG_WARN_AND_RETURN_VOID_UNLESS(iter != m_buildingList.end(), L"找不到要删除的单体",L"GDMPLab",L"2024-03-30");

    if (iter->buildingId.IsValid())
    {
        if (CanBuildingBeDeleted(m_pDoc, iter->buildingId) == false)
        {
            return;
        }
    }

    if (UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"是否确定删除单体及其楼层列表？"), (int)UiCommonDialog::ButtonType::OK | (int)UiCommonDialog::ButtonType::Cancel) == UiCommonDialog::ButtonType::OK)
    {
        if (iter->buildingId.IsValid())
        {
            m_deletedBuildings.push_back(iter->buildingId);
        }
        m_buildingList.erase(iter);
    }

    UpdateBuildingList();
    UpdateStoreyTable();
}

std::wstring StoreyManagementDlg::GetCurrentStoreyName() const 
{
    int row = ui->storeyTable->currentRow();
    DBG_WARN_AND_RETURN_UNLESS(row >=0 && row < ui->storeyTable->rowCount(), L"", L"当前行为空",L"GDMPLab",L"2024-03-30");

    QTableWidgetItem *item = ui->storeyTable->item(row, 1);
    DBG_WARN_AND_RETURN_UNLESS(item, L"", L"当前Item为空",L"GDMPLab",L"2024-03-30");

    return item->text().toStdWString();
}

StoreyList& StoreyManagementDlg::GetCurrentStoreyList()
{
    BuildingStruct& buildingStruct = GetCurrentBuildingStruct();
    return buildingStruct.storeyList;
}

BuildingStruct& StoreyManagementDlg::GetCurrentBuildingStruct()
{
    static BuildingStruct emptyBuildingStruct(L"", ElementId::InvalidID);
    FOR_EACH(buildingStruct, m_buildingList)
    {
        if (buildingStruct.name == m_currentBuildingName)
        {
            return buildingStruct;
        }
    }

    DBG_WARN(L"没有单体信息？",L"GDMPLab",L"2024-03-30");
    return emptyBuildingStruct;
}

StoreyList& StoreyManagementDlg::GetStoreyListByBuildingId(ElementId buildingId)
{
    static StoreyList emptyStoreyStruct;
    FOR_EACH(buildingStruct, m_buildingList)
    {
        if (buildingStruct.buildingId == buildingId)
        {
            return buildingStruct.storeyList;
        }
    }

    DBG_WARN(L"没有单体信息？",L"GDMPLab",L"2024-03-30");
    return emptyStoreyStruct;
}

void StoreyManagementDlg::OnBuildingListItemClicked(QListWidgetItem *pItem)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pItem, L"当前行为空",L"GDMPLab",L"2024-03-30");
    m_currentBuildingName = pItem->text().toStdWString();

    UpdateStoreyTable();
}

void StoreyManagementDlg::OnBuildingListItemChanged(QListWidgetItem* pItem)
{
    int row = ui->buildingListWidget->row(pItem);
    DBG_WARN_AND_RETURN_VOID_UNLESS(row >= 0 && row < m_buildingList.size(), L"修改的行数比总的单体数还多？",L"GDMPLab",L"2024-03-30");

    // 如果没改名， 直接返回
    if (pItem->text().toStdWString() == m_currentBuildingName)
    {
        return;
    }

    if (pItem->text().isEmpty() == false)
    {
        std::wstring name = pItem->text().toStdWString();
        if (IsBuildingNameExisted(name))
        {
            UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"单体名字已经存在"), (int)UiCommonDialog::ButtonType::OK);
            pItem->setText(QString::fromStdWString(m_currentBuildingName));
        }
        else
        {
            m_buildingList[row].name = name;
            m_currentBuildingName = name;
        }
    }
    else
    {
        pItem->setText(QString::fromStdWString(m_currentBuildingName));
    }
}

void StoreyManagementDlg::OnStoreyTableItemChanged(QTableWidgetItem* pItem)
{
    StoreyList& currentStoreyList = GetCurrentStoreyList();
    int column = ui->storeyTable->column(pItem);
    int row = ui->storeyTable->row(pItem);
    // 标高名
    if (column == 1)
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(row >= 0 && row < currentStoreyList.GetStoreyCount(), L"修改的行数比总的楼层数还多？",L"GDMPLab",L"2024-03-30");
        std::wstring oldName = pItem->data(LEVEL_NAME_DATA_ROLE).toString().toStdWString();
        std::wstring name = pItem->text().toStdWString();
        std::list<StoreyStruct>& storeyStructs = currentStoreyList.GetStoryListFW();
        for (auto iter = storeyStructs.begin(); iter != storeyStructs.end(); ++iter)
        {
            if (iter->name == oldName)
            {
                if (name.empty())
                {
                    UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"标高名字"), (int)UiCommonDialog::ButtonType::OK);
                    pItem->setText(QString::fromStdWString(iter->name));
                }
                // 当前行的名字如果改了
                if (iter->name != name)
                {
                    // 这个名字如果已经存在了
                    if (IsLevelNameExisted(name))
                    {
                        UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"标高名字已经存在"), (int)UiCommonDialog::ButtonType::OK);
                        pItem->setText(QString::fromStdWString(iter->name));
                    }
                    else
                    {
                        iter->name = name;
                        pItem->setData(LEVEL_NAME_DATA_ROLE, QVariant(QString::fromStdWString(name)));
                    }
                }
                return;
            }
        }
    }
    else if (column == 2) // 标高值
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(row == currentStoreyList.GetStoreyCount() - 1, L"只有起始标高可以改",L"GDMPLab",L"2024-03-30");
        currentStoreyList.SetStartElevation(pItem->text().toDouble() * 1000); // 转换成毫米
        std::wstring name;
        QTableWidgetItem* pLevelNameItem = ui->storeyTable->item(row, 1);
        if (pLevelNameItem)
        {
            name = pLevelNameItem->text().toStdWString();
        }
        
        UpdateStoreyTable(name);
    }
    else if (column == 3) // 楼层高度
    {
        double storeyHeight = pItem->text().toDouble() * 1000; // 转换成毫米
        
        QTableWidgetItem* pLevelNameItem = ui->storeyTable->item(row, 1);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pLevelNameItem, L"当前行的标高名字的Item不存在？",L"GDMPLab",L"2024-03-30");
        std::wstring name = pLevelNameItem->text().toStdWString();

        std::list<StoreyStruct>& storeyStructs = currentStoreyList.GetStoryListFW();
        for (auto iter = storeyStructs.begin(); iter != storeyStructs.end(); ++iter)
        {
            if (iter->name == name)
            {
                if (storeyHeight <= 0)
                {
                    UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"楼层高度要大于0"), (int)UiCommonDialog::ButtonType::OK);
                    pItem->setText(QString::number(iter->storeyHeight / 1000)); // 转换成米
                    return;
                }
                else
                {
                    iter->storeyHeight = storeyHeight;
                    UpdateStoreyTable(name);
                }
                return;
            }
        }
    }
}

bool StoreyManagementDlg::IsBuildingNameExisted(const std::wstring& name)
{
    for (auto iter = m_buildingList.begin(); iter != m_buildingList.end(); ++iter)
    {
        if (iter->name == name)
        {
            return true;
        }
    }

    return false;
}

bool StoreyManagementDlg::IsLevelNameExisted(const std::wstring& name)
{
    for (auto buildingIter = m_buildingList.begin(); buildingIter != m_buildingList.end(); ++buildingIter)
    {
        std::set<std::wstring> storeyNames = buildingIter->storeyList.GetStoreyNames();
        return storeyNames.find(name) != storeyNames.end();
    }

    return false;
}

void StoreyManagementDlg::UpdateStartIndexLineEdit(int index)
{
    int startIndex = index >= 0 ? index + 1 : index - 1;
    ui->startIndexLineEdit->setText(QString::number(startIndex));
}

bool StoreyManagementDlg::CheckAddStoreyInput()
{
    if (ui->startIndexLineEdit->text().isEmpty())
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"楼层起始不能为空。"), (int)UiCommonDialog::ButtonType::OK);
        return false;
    }

    if (m_startIndexValidator.ValidateValue(ui->startIndexLineEdit->text().toInt()) == false)
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"楼层起始请输入[-50, 200]的值"), (int)UiCommonDialog::ButtonType::OK);
        return false;
    }

    if (ui->storeyHeightLineEdit->text().isEmpty())
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"楼层层高不能为空。"), (int)UiCommonDialog::ButtonType::OK);
        return false;
    }

    if (m_heightValidator.ValidateValue(ui->storeyHeightLineEdit->text().toDouble()) == false)
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"楼层层高请输入[0, 100]的值"), (int)UiCommonDialog::ButtonType::OK);
        return false;
    }

    if (ui->storeyNumLineEdit->text().isEmpty())
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"楼层层数不能为空。"), (int)UiCommonDialog::ButtonType::OK);
        return false;
    }

    if (m_storeyNumValidator.ValidateValue(ui->storeyNumLineEdit->text().toInt()) == false)
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"楼层管理"), GBMP_TR(L"楼层层数请输入[1, 500]的值"), (int)UiCommonDialog::ButtonType::OK);
        return false;
    }
    return true;
}

void StoreyManagementDlg::keyPressEvent(QKeyEvent* event)
{
    if (event && event->type() == QEvent::KeyPress)
    {
        switch (event->key())
        {       
        case Qt::Key_Delete:
        {
            OnDeleteStoreyButtonPushed();
            break;
        }        
        default:
            break;
        }
    }
}
